/*
    kOTF Open Trace Format - a library for generating execution traces.
    Copyright 2012 Daniel K. O.

    kOTF is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    kOTF is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public License
    along with kOTF.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef KOTF_SESSION_H
#define KOTF_SESSION_H

#include <memory>


#include <boost/ptr_container/ptr_map.hpp>

#include <kotf/Types.hpp>
#include <kotf/Records.hpp>

#include <kotf/Error.hpp>

/**
   
 */

namespace kotf {

    class SessionImpl;
    class Stream;

    /** \brief trace session
        
        This is the root class that manages other objects. All member functions (except
        constructor and destructor, and enable()/disable()) are thread-safe. The get*() methods
        obviously require locking a per-session mutex, so the values should be cached somewhere.
        Streams are the only ones that can't be copyied.

        Handles created/queried by the session are identified by a 64-bit integer id. You can
        pass in an id and get the full object (with the name).

        Ideally you would have one session per program, or per run. Do not share State variables
        between sessions; the streams will output them, but no definition for them will be
        available.

        \note When the session is disabled, all the streams returned will be invalid and will
        produce no output. Do not write logic in your program depending on the stream's id or
        name. The same happens for states, counters and channels (so the lookup/creation
        while disabled is inexpensive).
     */
    class Session {
    private:
        SessionImpl *pimpl;
        friend class StreamImpl;

    public:
        /** \brief Construct a session with a specified name.

            @param sessname the session name. The file corresponding to this session will be named <sessname>.kotf
         */
        Session(const string& sessname);

        /** \brief Destroys a session, writing down the session file.

            This is a blocking function. The writing itself is done in a separated thread, so this
            waits for the writing thread to finish.

            \warning Do not destroy the session if any stream is still being used.
         */
        ~Session();

        void enable(); ///< Enable trace generation (default)

        /** \brief Disable trace generation.
            This function will block until the writer thread exits. Data traced so far may be lost,
            so this should be called right after construction of the session.
         */
        void disable();
        bool isEnabled() const; ///< wheter the session is enabled
        
        Stream& getStream(const string& s); ///< returns or constructs a new Stream with this name

        State getState(uint64_t st) throw (InvalidStateId); ///< returns an existing State or throws InvalidStateId
        State getState(const string& st); ///< returns or creates a new State

        Counter getCounter(uint64_t cnt) throw (InvalidCounterId); ///< returns an existing Counter or throws InvalidCounterId
        Counter getCounter(const string& cnt); ///< returns or creates a new Counter

        Channel getChannel(uint64_t ch) throw (InvalidChannelId); ///< returns an existing Channel or throws InvalidChannelId
        Channel getChannel(const string& ch); ///< returns or creates a new Channel


        uint64_t getTime() const; ///< returns the nanoseconds since the start of the session


        const string& getName() const;


        /** \brief returns a global session object, named after the program

            This session will be destroyed (and thus block) with the global destructors, when the
            program is exiting.

            This is an easier way to trace into libraries that do not have the control over the lifetime
            of the objects during the program execution. This function locks a mutex, so it is less
            efficient than creating your own Session object.
         */
        static Session& getDefault();
        
        /** sets the default session's name to something other than the program's name,
            if it was not already constructed. Otherwise returns the existing session.
         */
        static Session& setDefault(const string& name);

    };

}

#endif
